package com.capgemini.scaffold.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.capgemini.scaffold.common.BusinessException;
import com.capgemini.scaffold.common.ExceptionEnum;
import com.capgemini.scaffold.controller.UserController;
import com.capgemini.scaffold.mapper.DictMapper;
import com.capgemini.scaffold.model.Dict;
import com.capgemini.scaffold.model.request.AdminUpdateReq;
import com.capgemini.scaffold.model.request.UserUpdateReq;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import static com.capgemini.scaffold.constant.UserConstant.USER_LOGIN_STATE;
import com.capgemini.scaffold.mapper.UserMapper;
import com.capgemini.scaffold.model.User;
import com.capgemini.scaffold.model.request.UserReq;
import com.capgemini.scaffold.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private DictMapper dictMapper;
    /**
     * 盐值，混淆密码
     */
    private static final String SALT = "capgemini";

//    /**
//     * 用户登录态键
//     */
//    private static final String USER_LOGIN_STATE = "userLoginState";

//    @Override
//    public User add(User user) {
//        // 获取系统当前时间，即为默认创建时间和更新时间
//        Date date = new Date();
//        // 设置创建时间和更新时间
//        user.setUserCreateTime(date);
//        user.setUserUpdateTime(date);
//        // userAccount重复判断
//        LambdaQueryWrapper<User> qw = Wrappers.lambdaQuery();
//        qw.eq(User::getUserAccount, user.getUserAccount());
//        List<User> existUserAccount = userMapper.selectList(qw);
//        // 如果存在则抛出业务异常
//        if (CollectionUtils.isNotEmpty(existUserAccount)) {
//            throw new BusinessException(ExceptionEnum.DUPLICATE_USER_ACCOUNT);
//        }
//        // 插入用户信息
//        userMapper.insert(user);
//        return user;
//    }

    /**
     * 删除用户
     *
     * @param id
     * @return
     */
    @Override
    public boolean delete(Integer id) {
        User user = userMapper.selectById(id);
        if(user == null){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"该用户不存在！");
        }
        if(user.getIsDelete() == 1){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"该用户已被删除！");
        }
        if(user.getStatusId().equals("o")){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"该用户已处于项目中，不可删除！");
        }
        user.setIsDelete(1);
        userMapper.updateById(user);
        throw new BusinessException(ExceptionEnum.SUCCESS);
    }

    /**
     * 更新用户信息
     *
     * @param adminUpdateReq
     * @return
     */
    @Override
    public int update(AdminUpdateReq adminUpdateReq) {
        System.out.println(adminUpdateReq);
        User user = new User();
        // 获取系统当前时间，即为更新时间
        Date date = new Date();
        // 设置更新时间
        adminUpdateReq.setUserUpdateTime(date);
        //更新
        user = userMapper.selectById(adminUpdateReq.getUserId());
        QueryWrapper<Dict> qwD = new QueryWrapper<>();
        qwD.eq("dict_name",adminUpdateReq.getDepaetment());
        String departmentId=dictMapper.selectOne(qwD).getDictId();
        user.setDepartmentId(departmentId);
        QueryWrapper<Dict> qwP = new QueryWrapper<>();
        qwP.eq("dict_name",adminUpdateReq.getPosition());
        String positionId = dictMapper.selectOne(qwP).getDictId();
        user.setPositionId(positionId);

        userMapper.updateById(user);
        //加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + user.getUserPassword()).getBytes());
        //异常处理
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_password",encryptPassword);
        if(userMapper.selectCount(queryWrapper) == 1){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"修改密码不能与上一次相同");
        }
        user.setUserPassword(encryptPassword);
        user.setUserName(adminUpdateReq.getUserName());
        user.setUserEmail(adminUpdateReq.getUserEmail());
        user.setUserPhone(adminUpdateReq.getUserPhone());
        return userMapper.updateById(user);
    }

    @Override
    public int userUpdate(UserUpdateReq userUpdateReq){
        // 获取系统当前时间，即为更新时间
        Date date = new Date();
        // 设置更新时间
        userUpdateReq.setUserUpdateTime(date);
        //加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userUpdateReq.getUserPassword()).getBytes());
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userUpdateReq.getUserName())
                .eq("user_password",encryptPassword)
                .eq("user_phone",userUpdateReq.getUserPhone())
                .eq("user_email",userUpdateReq.getUserEmail())
                .eq("user_account",userUpdateReq.getUserAccount());
        if(userMapper.selectCount(queryWrapper) == 1){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"没有进行修改");
        }
        //插入数据
        User user = userMapper.selectById(userUpdateReq.getUserId());
        user.setUserPassword(encryptPassword);
        user.setUserAccount(userUpdateReq.getUserAccount());
        user.setUserName(userUpdateReq.getUserName());
        user.setUserEmail(userUpdateReq.getUserEmail());
        user.setUserPhone(userUpdateReq.getUserPhone());
        return userMapper.updateById(user);
    }
    /**
     * 获取用户信息
     *
     * @param id
     * @return
     */
    @Override
    public User get(Integer id) {
        return userMapper.selectById(id);
    }

    /**
     * 获取leader列表
     * @return
     */
    public List<User> getLeader(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("level_id","l")
                .eq("status_id","b");
        return userMapper.selectList(queryWrapper);
    }

    /**
     * 获取未在项目的员工表
     * @return
     */
    public List<User> getEmployee(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("level_id","em")
                .eq("status_id","b");
        return userMapper.selectList(queryWrapper);
    }

    /**
     * 查询用户信息表，入参均为非必填
     *   userAccount：精确查询
     *   userName：模糊查询
     *   startTime：CREATE_AT 大于等于 startTime
     *   endTime：CREATE_AT 小于 endTime
     *
     * @param req 查询请求入参对象
     * @return 用户信息列表
     */
    @Override
    public List<User> queryUser(UserReq req) {
        return userMapper.queryUser(req);
    }


    /**
     * 根据id查询
     *
     * @param userId
     * @return
     */
    @Override
    public User queryUserById(Integer userId){
       return userMapper.selectById(userId);
    }

//    /**
//     * 分页查询用户信息
//     *
//     * @param req 查询请求入参
//     * @return 查询结果
//     */
//    @Override
//    public IPage<User> queryUserPage(UserReq req) {
//        //封装分页信息，第一个参数页码值、第二个参数每页显示数量
//        Page<User> page = new Page<>(req.getPageNum(), req.getPageSize());
//        //进行分页查询
//        IPage<User> pageList = userMapper.queryUser(page, req);
//        //获取分req
//        return pageList;
//    }

    /**
     * 用户注册
     *
     * @param userAccount
     * @param userPassword
     * @param checkPassword
     * @return
     */
    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String userName, String positionName) {
        //数字
        String REG_NUMBER = ".*\\d+.*";
        //大写字母
        String REG_UPPERCASE = ".*[A-Z]+.*";
        //小写字母
        String REG_LOWERCASE = ".*[a-z]+.*";
        //特殊字符
        String REG_SYMBOL = "[`~!@#$%^&()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&（）——+|{}【】‘；：”“’。，、？] ";
        //账户，密码和校验密码是否为空
        if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"参数为空");
        }
        //密码长度至少6位
        if(userPassword.length() < 6){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"密码小于6位");
        }
        //密码必须包含数字和字母
        if(!userPassword.matches(REG_NUMBER) && ((userPassword.matches(REG_UPPERCASE)) || (userPassword.matches(REG_LOWERCASE)))){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"密码必须包含数字和字母");
        }
        //密码和校验密码必须相同
        if(!userPassword.equals(checkPassword)){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"两次输入密码不一致");
        }
        //账户不能包含特殊字符
        Matcher matcher = Pattern.compile(REG_SYMBOL).matcher(userAccount);
        if(matcher.find()){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"账号不能包含特殊字符");
        }
        //账户不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account",userAccount);
        long count = userMapper.selectCount(queryWrapper);
        if(count > 0){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"该用户已存在");
        }
        //加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        User user = new User();
        // 获取系统当前时间，即为更新时间
        Date date = new Date();
        // 设置创建时间
        user.setUserCreateTime(date);
        //插入数据
        user.setUserAccount(userAccount);
        user.setUserGender(1);
        user.setLevelId("em");
        user.setStatusId("b");
        user.setUserEntryTime(new Date());
        user.setUserPassword(encryptPassword);
        user.setUserName(userName);
        user.setPositionId(dictMapper.selectById(positionName).getDictId());
        boolean saveResult = this.save(user);
        if(!saveResult){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"保存错误");
        }
        return user.getUserId();
    }


    /**
     * 用户登录
     *
     * @param userAccount
     * @param userPassword
     * @param request
     * @return
     */
    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        //数字
        String REG_NUMBER = ".*\\d+.*";
        //大写字母
        String REG_UPPERCASE = ".*[A-Z]+.*";
        //小写字母
        String REG_LOWERCASE = ".*[a-z]+.*";
        //特殊字符
        String REG_SYMBOL = "[`~!@#$%^&()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&（）——+|{}【】‘；：”“’。，、？] ";
        //账户，密码是否为空
        if(StringUtils.isAnyBlank(userAccount,userPassword)){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"参数为空");
        }
        //密码长度至少6位
        if(userPassword.length() < 6){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"密码小于6位");
        }
        //密码必须包含数字和字母
        if(!userPassword.matches(REG_NUMBER) && ((userPassword.matches(REG_UPPERCASE)) || (userPassword.matches(REG_LOWERCASE)))){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"密码必须包含数字和字母");
        }
        //账户不能包含特殊字符
        Matcher matcher = Pattern.compile(REG_SYMBOL).matcher(userAccount);
        if(matcher.find()){
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"密码不能包含特殊字符");
        }
        //加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        //匹配账号密码
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account",userAccount)
                    .eq("user_password",encryptPassword);
        User user = userMapper.selectOne(queryWrapper);
        //用户不存在
        if(user == null){
            log.info("user login failed,userAccount cannot match userPassword!");
            throw new BusinessException(ExceptionEnum.PARAMS_ERROR,"用户账号与密码不匹配");
        }

        //用户信息脱敏
        User safetyUser = getsafetyUser(user);

        //记录用户登录态
        request.getSession().setAttribute(USER_LOGIN_STATE + "",safetyUser);

        return safetyUser;
    }

    /**
     * 用户信息脱敏
     *
     * @param originUser
     * @return
     */
    @Override
    public User getsafetyUser(User originUser){
        if(originUser == null){
            return null;
        }
        User safetyUser = new User();
        safetyUser.setUserId(originUser.getUserId());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setUserName(originUser.getUserName());
        safetyUser.setUserGender(originUser.getUserGender());
        safetyUser.setUserPhone(originUser.getUserPhone());
        safetyUser.setUserEmail(originUser.getUserEmail());
        safetyUser.setDepartmentId(originUser.getDepartmentId());
        safetyUser.setPositionId(originUser.getPositionId());
        safetyUser.setLevelId(originUser.getLevelId());
        safetyUser.setProjectId(originUser.getProjectId());
        safetyUser.setStatusId(originUser.getStatusId());
        safetyUser.setUserAvatarUrl(originUser.getUserAvatarUrl());
        safetyUser.setUserEntryTime(originUser.getUserEntryTime());
        safetyUser.setUserCreateTime(originUser.getUserCreateTime());
        safetyUser.setIsRole(originUser.getIsRole());
        return safetyUser;
    }

    /**
     * 获取头像文件存入数据库
     * @param uploadFile
     * @param userId
     * @return
     */
    @Override
    public String saveImg(MultipartFile uploadFile,Integer userId) {
        final Logger logger = LoggerFactory.getLogger(UserController.class);

        // 项目根路径下的目录  -- SpringBoot static 目录相当于是根路径下（SpringBoot 默认）
        final String UPLOAD_PATH_PREFIX = "static/uploadFile/";
        if(uploadFile.isEmpty()){
            //返回选择文件提示
            return "请选择上传文件";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
        //构建文件上传所要保存的"文件夹路径"--这里是相对路径，保存到项目根路径的文件夹下
        String realPath = new String("src/main/resources/" + UPLOAD_PATH_PREFIX);
        logger.info("-----------上传文件保存的路径【"+ realPath +"】-----------");
        String format = sdf.format(new Date());
        //存放上传文件的文件夹
        File file = new File(realPath + format);
        logger.info("-----------存放上传文件的文件夹【"+ file +"】-----------");
        logger.info("-----------输出文件夹绝对路径 -- 这里的绝对路径是相当于当前项目的路径而不是“容器”路径【"+ file.getAbsolutePath() +"】-----------");
        if(!file.isDirectory()){
            //递归生成文件夹
            file.mkdirs();
        }
        //获取原始的名字  original:最初的，起始的  方法是得到原来的文件名在客户机的文件系统名称
        String oldName = uploadFile.getOriginalFilename();
        logger.info("-----------文件原始的名字【"+ oldName +"】-----------");
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."),oldName.length());
        logger.info("-----------文件要保存后的新名字【"+ newName +"】-----------");
        File newFile = new File(file.getAbsolutePath() + File.separator + newName);
        try {
            uploadFile.transferTo(newFile);
            // 1. 创建一个FtpClient对象
            FTPClient ftpClient = new FTPClient();
            // 2. 创建 ftp 连接
//            ftpClient.connect("localhost", 21);
            ftpClient.connect("101.35.94.229", 21);
            // 3. 登录 ftp 服务器
            ftpClient.login("ftpuser", "user123");
            // 4. 读取本地文件
            FileInputStream inputStream = new FileInputStream(new File(file.getAbsolutePath() + File.separator + newName));
            // 5. 设置上传的路径
            ftpClient.changeWorkingDirectory("/health/images");
            // 6. 修改上传文件的格式为二进制
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            // 7. 服务器存储文件，第一个参数是存储在服务器的文件名，第二个参数是文件流
            ftpClient.storeFile(newName, inputStream);
            // 8. 关闭连接
            ftpClient.logout();
        }catch (IOException e) {
            throw new RuntimeException(e);
        }
        User user=userMapper.selectById(userId);
        user.setUserAvatarUrl("http://101.35.94.229:888/images/"+newName);
        userMapper.updateById(user);

        return "http://101.35.94.229:888/images/"+newName;
    }

}
